﻿using System;
using System.Collections.Generic;


namespace Tea.Parser {

    //  Statement : See clause 12
    //    Block
    //    VariableStatement
    //    EmptyStatement
    //    ExpressionStatement
    //    IfStatement
    //    IterationStatement
    //    ContinueStatement
    //    BreakStatement
    //    ReturnStatement
    //    WithStatement
    //    LabelledStatement
    //    SwitchStatement
    //    ThrowStatement
    //    TryStatement

    /// <summary>
    /// 表示 label 集合。
    /// </summary>
    public sealed class LabelSet {

        sealed class Entry{

            public Identifier Name;

            public Entry Next;
        }

        Entry _first;

        public bool Add(Identifier Name) {

            bool exits = false;
            
            if (_first != null) {
                for (Entry current = _first; current.Next != null; current = current.Next) {
                    if (current.Name == Name) {
                        exits = true;
                    }
                    current.Next = new Entry { Name = Name };
                }
            } else {
                _first = new Entry() { Name = Name };
            }


            return exits;
        }

        public bool Contains(Identifier name) {
            for (Entry current = _first; current != null; current = current.Next) {
                if (current.Name == name)
                    return true;
            }

            return false;
        }

        public bool Remove(Identifier name) {

            bool success = false;
            if (_first != null) {
                if (_first.Name == name) {
                    success = true;
                    _first = null;
                } else {
                    for (Entry current = _first; current.Next != null; current = current.Next) {
                        if (current.Next.Name == name) {
                            current.Next = current.Next.Next;
                            success = true;
                            break;
                        }
                    }
                }
            }


            return success;
        }

        public bool Contains(string name) {
            for (Entry current = _first; current != null; current = current.Next) {
                if (current.Name.Name == name)
                    return true;
            }

            return false;
        }

        public bool IsEmpty {
            get {
                return _first == null;
            }
        }

        public LabelSet Clone() {
            LabelSet ls = new LabelSet();
            ls._first = _first;
            return ls;
        }
    }

    /// <summary>
    /// 表示一个可中断的语句。
    /// </summary>
    public abstract class BreakableStatement :Statement {

        /// <summary>
        /// 获取或设置当前的父语句块。
        /// </summary>
        public BreakableStatement Parent {
            get;
            set;
        }

        LabelSet _labels;

        /// <summary>
        /// 获取标签。
        /// </summary>
        public LabelSet Labels {
            get{
                if (_labels == null) {
                    _labels = new LabelSet();
                }

                return _labels;
            }
            private set {
                if (value != null) {
                    _labels = value.Clone();
                }
            }
        }

        /// <summary>
        /// 初始化 <see cref="Tea.Parser.BreakableStatement"/> 的新实例。
        /// </summary>
        /// <param name="breakTarget">中断后的目标语句。</param>
        /// <param name="label">标签。</param>
        /// <param name="location">开始位置。</param>
        /// <param name="endLocation">结束位置。</param>
        public BreakableStatement(LabelSet labels, Location location)
            : base(location) {
                Labels = labels;
        }

    }

    // Block:
    //  { StatementList }
    //  StatementList

    // StatementList:
    //   Statement
    //   StatementList Statement

    public class ConstStatement :VariableStatement {
        

        public ConstStatement(NodeList<VariableDeclaration> s, Location location, Location endLocation)
            : base(s, location, endLocation) {
            
        }


        protected override string DeclString {
            get {
                return "const";
            }
        }

        [System.Diagnostics.DebuggerStepThrough]
        public override void Accept(IAstVisitor visitor) {
            visitor.VisitConstStatement(this);
        }
    }

    public class FunctionDeclaration : Statement, IScopeNode {

        public string Name {
            get {
                return Function.Name;
            }
        }

        public NodeList<Statement> Statements {
            get {
                return Function.Statements;
            }
        }

        public FunctionExpression Function {
            get;
            private set;
        }

        public override Location EndLocation {
            get {
                return Function.EndLocation;
            }
        }

        public FunctionDeclaration(FunctionExpression function)
            : base(function.StartLocation) {
            Function = function;
        }

        public override void Write(IndentedTextWriter writer) {
            Function.Write(writer);

            base.Write(writer);
        }

        public override void Accept(IAstVisitor visitor) {
            visitor.VisitFunctionDeclaration(this);
        }

        #region IScopeNode 成员


        public void AddSymbol(string name, TokenType declType) {
            Function.AddSymbol(name, declType);
        }

        public TokenType GetSymbol(string name) {
            return Function.GetSymbol(name);
        }

        public IScopeNode GetDefinedBlock(string name) {
            return Function.GetDefinedBlock(name);
        }

        public void AddFunction(FunctionDeclaration fn) {
            Function.AddFunction(fn);
        }

        public NodeList<FunctionDeclaration> Functions {
            get {
                return Function.Functions;
            }
        }

        #endregion
    }

}
